#include "../Logging.h"
namespace yhaida
{
    __thread char thread_Erro[512];
    __thread char thread_Time[32];
    __thread time_t thread_LastSecond; //缓存秒数

    Logging::LogLevel initLogLevel()
    {
        if (getenv("work"))
        {
            return Logging::LogLevel::TRACE;
        }
        else
        {
            return Logging::LogLevel::DEBUG;
        }
    }
    void defaultOutput(const char *str, int length)
    {
        size_t n = fwrite(str, 1, length, stdout);
        if (n < 0)
        {
            abort();
        }
    }
    void defaultFlush()
    {
        fflush(stdout);
    }
    //全局变量的定义
    Logging::LogLevel global_logLevel = initLogLevel();
    Logging::OutputFunc global_outPut = defaultOutput;
    Logging::FlushFunc global_flush = defaultFlush;

    //定义个数组方便读写
    const char *LogLevelName[Logging::LogLevel::NUM_LOG_LEVELS] =
        {
            "TRACE ",
            "DEBUG ",
            "INFO  ",
            "WARN  ",
            "ERROR ",
            "FATAL ",
    };
    //根据错误码翻译成字符串并且在缓存中备份。
    const char *strerror_tl(int savedErrno)
    {
        return strerror_r(savedErrno, thread_Erro, sizeof(thread_Erro));
    }
}
//***********************************class Logging::Impl***********************************
using namespace yhaida;
// errno(这是一个宏)->savedErrno
Logging::Impl::Impl(LogLevel level, int savedErrno, const char *file, int line)
    : _time(Timestamp::now()),
      _level(level),
      _stream(),
      _line(line),
      _fullName(file),
      _baseName(NULL)
{
    const char *p = strrchr(_fullName, '/');
    _baseName = p ? p + 1 : _fullName;
    //日期 时间 微妙
    formatTime();
    //线程
    Fmt tid("%6d", CurrentThread::tid());
    assert(tid.length() == 6);
    // class T是为了统一化输入格式(const char*，length)
    _stream << Detail::T(tid.data(), 6) << ' ';
    //级别
    _stream << Detail::T(LogLevelName[_level], 6);
    //正文
    if (savedErrno)
    {
        _stream << strerror_tl(savedErrno) << " (errno" << savedErrno << ") ";
    }
}

void Logging::Impl::formatTime()
{
    int64_t nowTime = _time.microSecondsSinceEpoch();
    time_t nowSecond = static_cast<time_t>(nowTime / (1000 * 1000));
    int nowMicroSecond = static_cast<int>(nowTime % (1000 * 1000));
    //缓存秒，即微妙
    if (thread_LastSecond != nowSecond)
    {
        thread_LastSecond = nowSecond;
        struct tm tm_time;
        gmtime_r(&nowSecond, &tm_time); // UTC

        int length = snprintf(thread_Time, sizeof(thread_Time),
                              "%4d%02d%02d %02d:%02d:%02d", tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
                              tm_time.tm_hour + 8, tm_time.tm_min, tm_time.tm_sec);
        assert(length == 17);
    }
    Fmt fmt(".%06dZ", nowMicroSecond);
    // printf("%d\n",fmt.length());
    assert(fmt.length() == 8);
    _stream << Detail::T(thread_Time, 17) << ':' << Detail::T(fmt.data(), fmt.length());
}
// - 源文件：行号
void Logging::Impl::finish()
{
    _stream << " - " << _baseName << ':' << _line << '\n';
}

//***********************************class Logging***********************************
Logging::Logging(const char *file, int line)
    : _impl(Logging::LogLevel::INFO, 0, file, line)
{
}
Logging::Logging(int savedErrno, const char *file, int line)
    : _impl(savedErrno ? Logging::LogLevel::FATAL : Logging::LogLevel::ERROR, errno, file, line)
{
}
Logging::Logging(LogLevel level, const char *file, int line)
    : _impl(level, 0, file, line)
{
}
Logging::Logging(LogLevel level, const char *file, int line, const char *func)
    : _impl(level, 0, file, line)
{
    //正文
    _impl._stream << func << ' ';
}

Logging::~Logging()
{
    _impl.finish();
    const LogStream::Buffer &buff(stream().buffer());
    global_outPut(buff.data(), buff.length());
    if (_impl._level == Logging::LogLevel::FATAL)
    {
        global_flush();
        abort();
    }
}
// static成员函数声明为inline会报undefined reference to `*******'错误
Logging::LogLevel Logging::logLevel()
{
    return global_logLevel;
}
// static成员函数声明为inline会报undefined reference to `*******'错误
void Logging::setLogLevel(LogLevel level)
{
    global_logLevel = level;
}
// static成员函数声明为inline会报undefined reference to `*******'错误
void Logging::setOutput(OutputFunc func)
{
    global_outPut = func;
}
// static成员函数声明为inline会报undefined reference to `*******'错误
void Logging::setFlush(FlushFunc func)
{
    global_flush = func;
}
